/* -*- P4_16 -*- */
#include <core.p4>
#include <v1model.p4>

// 协议常量定义
const bit<8>  PROTO_TCP = 0x06;
const bit<16> ETH_TYPE_IPV4 = 0x800;

/*************************************************************************
*********************** 头部定义 ***********************************
*************************************************************************/

typedef bit<9>  PortId;         // 端口标识类型
typedef bit<48> MacAddr;        // MAC地址类型
typedef bit<32> Ip4Addr;        // IPv4地址类型

// 以太网头部
header EthernetHdr {
    MacAddr dst;
    MacAddr src;
    bit<16> type;
}

// CPU监控头部（用于克隆包）
header CpuHdr {
    bit<8> ecn_flag;
}

// IPv4头部（包含ECN字段）
header Ipv4Hdr {
    bit<4>    version;
    bit<4>    ihl;
    bit<6>    diffserv;
    bit<2>    ecn;              // ECN标记位（00=未使用，10/01=支持ECN，11=拥塞）
    bit<16>   total_len;
    bit<16>   id;
    bit<3>    flags;
    bit<13>   frag_off;
    bit<8>    ttl;
    bit<8>    protocol;
    bit<16>   checksum;
    Ip4Addr   src;
    Ip4Addr   dst;
}

// 元数据结构
struct Metadata {
}

// 头部集合
struct Headers {
    EthernetHdr eth;
    CpuHdr      cpu;
    Ipv4Hdr     ipv4;
}

/*************************************************************************
*********************** 解析器 ***********************************
*************************************************************************/

parser PacketParser(
    packet_in packet,
    out Headers hdr,
    inout Metadata meta,
    inout standard_metadata_t std_meta
) {
    state start {
        transition parse_ethernet;
    }

    state parse_ethernet {
        packet.extract(hdr.eth);
        transition select(hdr.eth.type) {
            ETH_TYPE_IPV4: parse_ipv4;
            default: accept;
        }
    }

    state parse_ipv4 {
        packet.extract(hdr.ipv4);
        transition accept;
    }
}

/*************************************************************************
************** 校验和验证 ***********************************
*************************************************************************/

control ChecksumVerifier(
    inout Headers hdr,
    inout Metadata meta
) {
    apply { }
}

/*************************************************************************
************** 入口处理 ***********************************
*************************************************************************/

control IngressProcessor(
    inout Headers hdr,
    inout Metadata meta,
    inout standard_metadata_t std_meta
) {
    // 丢弃动作
    action drop_packet() {
        mark_to_drop(std_meta);
    }

    // IPv4转发动作
    action forward_ipv4(MacAddr dst_mac, PortId out_port) {
        std_meta.egress_spec = out_port;
        hdr.eth.src = hdr.eth.dst;  // 交换MAC地址
        hdr.eth.dst = dst_mac;
        hdr.ipv4.ttl = hdr.ipv4.ttl - 1;  // 减少TTL
    }

    // IPv4路由表（最长前缀匹配）
    table ipv4_route_table {
        key = {
            hdr.ipv4.dst: lpm;  // 匹配目的IP
        }
        actions = {
            forward_ipv4;
            drop_packet;
            NoAction;
        }
        size = 1024;
        default_action = NoAction();
    }

    apply {
        if (hdr.ipv4.isValid()) {
            ipv4_route_table.apply();  // 处理IPv4包
        }
    }
}

/*************************************************************************
************** 出口处理（核心ECN逻辑） ***********************************
*************************************************************************/

control EgressProcessor(
    inout Headers hdr,
    inout Metadata meta,
    inout standard_metadata_t std_meta
) {
    // 动态标记ECN：根据队列长度阈值修改ECN字段
    action set_ecn(bit<19> queue_threshold) {
        // 若队列深度超过阈值，标记ECN为11（拥塞）
        if (std_meta.enq_qdepth >= queue_threshold) {
            hdr.ipv4.ecn = 3;  // 二进制11
        }
        // 克隆数据包到控制器（用于监控）
        clone_preserving_field_list(CloneType.E2E, 100, 0);
    }

    // ECN检查表（由控制面动态配置阈值）
    table ecn_check_table {
        actions = {
            set_ecn;  // 动态传入阈值参数
            NoAction;
        }
        default_action = NoAction();
    }
    
    apply {
        // 处理正常数据包（instance_type=0表示原始包）
        if (std_meta.instance_type == 0) {
            // 仅对支持ECN的包（ECN=01或10）应用规则
            if (hdr.ipv4.ecn == 1 || hdr.ipv4.ecn == 2) {
                ecn_check_table.apply();
            }
        }

        // 处理克隆到控制器的包（instance_type=2表示出口克隆）
        if (std_meta.instance_type == 2) {
            hdr.cpu.setValid();
            hdr.cpu.ecn_flag = (bit<8>)hdr.ipv4.ecn;  // 携带ECN标记
            truncate((bit<32>)15);  // 截断包，仅保留必要头部
        }
    }
}

/*************************************************************************
************** 校验和计算 ***********************************
*************************************************************************/

control ChecksumCalculator(
    inout Headers hdr,
    inout Metadata meta
) {
    apply {
        update_checksum(
            hdr.ipv4.isValid(),
            {
                hdr.ipv4.version,
                hdr.ipv4.ihl,
                hdr.ipv4.diffserv,
                hdr.ipv4.ecn,
                hdr.ipv4.total_len,
                hdr.ipv4.id,
                hdr.ipv4.flags,
                hdr.ipv4.frag_off,
                hdr.ipv4.ttl,
                hdr.ipv4.protocol,
                hdr.ipv4.src,
                hdr.ipv4.dst
            },
            hdr.ipv4.checksum,
            HashAlgorithm.csum16
        );
    }
}

/*************************************************************************
************** 解解析器 ***********************************
*************************************************************************/

control PacketDeparser(
    packet_out packet,
    in Headers hdr
) {
    apply {
        packet.emit(hdr.eth);
        packet.emit(hdr.cpu);
        packet.emit(hdr.ipv4);
    }
}

/*************************************************************************
************** 交换机整体定义 ***********************************
*************************************************************************/

V1Switch(
    PacketParser(),
    ChecksumVerifier(),
    IngressProcessor(),
    EgressProcessor(),
    ChecksumCalculator(),
    PacketDeparser()
) main;